#pragma once 

#include <iostream>
#include <string>
#include <unordered_map>
#include <unistd.h>
#include <sys/epoll.h>

#define SIZE 128
#define NUM 64

class Event;
class Reactor;

//函数指针类型,返回值是int,传入的参数的类型是Event*的函数的类型
//其实这里设计的int返回值不太好,就自己写的代码来说其实可以用void作为返回值,这里的int返回我还没有用到过
typedef int(*callback_t)(Event* p_ev);

class Event
{
public:
    Event()
    :_sock(-1)
     , _inbuffer()
     , _outbuffer()
     , _recver(nullptr)
     , _sender(nullptr)
     , _errorer(nullptr)
     , _p_reactor(nullptr)
    {}

    //设置Event对应的回调函数
    void register_callback(callback_t recver, callback_t sender, callback_t errorer)
    {
        _recver = recver;
        _sender = sender;
        _errorer = errorer;
    }

public:
    //对应的文件描述符
    int _sock;
    //sock所对应的输入缓冲区
    std::string _inbuffer;
    //sock所对应的输出缓冲区
    std::string _outbuffer;
    //sock设置的回调函数
    //一般我们处理IO的时候,我们只有三种接口需要进行处理
    //处理读取
    //处理写入
    //处理异常
    callback_t _recver;
    callback_t _sender;
    callback_t _errorer;

    //用来回指Reactor对象的指针
    Reactor* _p_reactor;
};

//首先我们需要明确,Reactor不需要关注的sock的类型,listen,读和写都可以
//Reactor类,需要对Event进行管理
//Reactor : Event = 1 : n;

class Reactor
{
public:
    Reactor()
    :_epfd(-1)
     , _events()
    {}

    void init_reactor()
    {
        _epfd = epoll_create(SIZE);
        if (_epfd < 0)
        {
            std::cerr << "epoll create error" << std::endl;
            exit(6);
        }
        std::cout <<"init_reactor success" << std::endl;
    }

    bool insert_event(Event* p_ev, uint32_t evs)
    {
        //将需要监听的sock和对应的事件,插入到epoll中
        struct epoll_event ev;
        ev.events = evs;
        ev.data.fd = p_ev->_sock;
        if (epoll_ctl(_epfd, EPOLL_CTL_ADD, p_ev->_sock, &ev) < 0)
        {
            std::cerr << "epoll_ctl add event failed" << std::endl;
            return false;
        }
        else
        {
            std::cout << p_ev->_sock << "already hosted with epoll" << std::endl;
        }
        //将p_ev所指向的Event插入到unordered_map中
        _events.insert({p_ev->_sock, p_ev});
        return true;
    }

    bool delete_event(Event* p_ev)
    {
        int sock = p_ev->_sock;
        auto it = _events.find(sock);
        if (it != _events.end())
        {
            //删除epoll中监听的sock和其对应的事件
            if (epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr) < 0)
            {
                std::cerr << "epoll_ctl delete event failed" << std::endl;
                return false;
            }
            else
            {
                std::cout << p_ev->_sock << "has been removed by epoll" << std::endl;
            }
            //将p_ev所指向的Event从unordered_map中删除
            _events.erase(it);

            //关闭对应的sock
            close(sock);

            //删除Event节点
            delete p_ev;
        }
        return true;
    }

    //这个函数的关于epoll的修改的,可以改变监听的sock所关心的事件
    bool modify_read_write(int sock, bool enable_read, bool enable_write)
    {
        struct epoll_event ev;
        ev.data.fd = sock;
        ev.events = EPOLLET | (enable_read ? EPOLLIN : 0) | (enable_write ? EPOLLOUT : 0);

        if (epoll_ctl(_epfd, EPOLL_CTL_MOD, sock, &ev) < 0)
        {
            std::cerr << "epoll_ctl modify failed" << std::endl;
            return false;
        }
        return true;
    }

    //判断Reactor中是否有这个事件,或者可以认为是epoll是否监视这个事件
    bool reactor_have_event(int sock)
    {
        auto it = _events.find(sock);
        if (it != _events.end())
        {
            return true;
        }
        return false;
    }

    //就绪事件派发器
    void dispatcher(int timeout)
    {
        struct epoll_event revs[NUM];
        int n = epoll_wait(_epfd, revs, NUM, timeout);
        //使用for循环,只要n = 0或者是n < 1都不会进入这个循环
        for (int i = 0; i < n; ++i)
        {
            int sock = revs[i].data.fd;
            uint32_t revents = revs[i].events;

            //这里代表进行差错(异常)处理,epoll监视的sock中,不需要设置去监视异常,sock发生异常会自动通知的,我们这里将所有的错误问题转换成为下面的IO处理来进行解决
            if (revents & EPOLLERR)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }
            if (revents & EPOLLHUP)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }

            //代表读写事件就绪
            if (revents & EPOLLIN)
            {
                //调用Event对应的回调函数,执行相应的操作
                //在此之前还需要判断一下,现在所使用的sock,是否还在Reactor中存在,不然的话,进行unordered_map访问的时候,会进行插入
                if (reactor_have_event(sock) && _events[sock]->_recver)
                {
                    //到这里说明有对应的回调函数,可以执行
                    _events[sock]->_recver(_events[sock]);
                }
            }
            if (revents &EPOLLOUT)
            {
                if (reactor_have_event(sock) && _events[sock]->_sender)
                {
                    _events[sock]->_sender(_events[sock]);
                }
            }
        }
    }


private:
    int _epfd;
    //用来管理sock所对应的Event,其实也可以不同unordered_map来进行管理的
    //也可以用epoll_event结构体里面的data中的void* ptr,来进行解决,这里使用unordered_map看着更加的直观
    std::unordered_map<int, Event*> _events;
};


